import React, { ReactElement, useEffect, useMemo, useState } from 'react';
import {
  Animated,
  Easing,
  ImageStyle,
  Text,
  View,
  ViewStyle,
  Image
} from 'react-native';

import styles from './style';
import { classRoomGold } from '../../../../constant/resource';
import { phonePx } from '../../../../util/adapt';
import { CLASS_ROOM_RIGHT_SCALE } from '../../constant';
import { playSoundWithUrl } from '../../../../util/sound';

interface GetCoinAnimateProps {
  addGoldCoinNum: number;
  clearGoldCoinNum: () => void;
  hideGoldCoinNum?: () => void;
  style?: ViewStyle | ViewStyle[];
  coinStyle?: ImageStyle | ImageStyle[];
  showAddNumber?: boolean;
  width?: number;
  height?: number;
  x?: number;
  y?: number;
  scale: number;
  needSound?: boolean;
  children?: any;
  needBaseGoldCoin?: boolean;
}

export default ({
  addGoldCoinNum,
  clearGoldCoinNum,
  hideGoldCoinNum,
  style,
  coinStyle,
  showAddNumber = true,
  width = Math.floor(phonePx(18) * CLASS_ROOM_RIGHT_SCALE),
  height = Math.floor(phonePx(18) * CLASS_ROOM_RIGHT_SCALE),
  x = phonePx(15.5) * CLASS_ROOM_RIGHT_SCALE,
  y = phonePx(18) * CLASS_ROOM_RIGHT_SCALE,
  scale,
  needSound = true,
  children,
  needBaseGoldCoin = false
}: GetCoinAnimateProps): ReactElement => {
  const [animations, setAnimations] = useState<
    {
      addAnimation: Animated.ValueXY;
      scaleAnimation: Animated.Value;
      opacityAnimation: Animated.Value;
      animation: Animated.CompositeAnimation;
    }[]
  >([]);
  const [localShowAddNumber, setLocalShowAddNumber] = useState<boolean>(true);

  useEffect((): void => {
    const newAnimations = [];
    for (let i = 0; i < addGoldCoinNum; i += 1) {
      const scaleAnimation: Animated.Value = new Animated.Value(1);
      const opacityAnimation: Animated.Value = new Animated.Value(1);
      const addAnimation: Animated.ValueXY = new Animated.ValueXY({
        x: phonePx(0),
        y: phonePx(0)
      });
      const animation = Animated.parallel([
        Animated.timing(
          addAnimation, // Auto-multiplexed
          {
            toValue: {
              x,
              y
            },
            duration: 500,
            easing: Easing.cubic,
            useNativeDriver: true,
            delay: 200
          }
        ),
        i === addGoldCoinNum - 1
          ? Animated.spring(
              scaleAnimation, // Auto-multiplexed
              {
                toValue: scale,
                useNativeDriver: true,
                friction: 1,
                delay: 700
              }
            )
          : Animated.timing(
              scaleAnimation, // Auto-multiplexed
              {
                toValue: scale,
                duration: 500,
                easing: Easing.cubic,
                useNativeDriver: true,
                delay: 200
              }
            ),
        Animated.timing(
          opacityAnimation, // Auto-multiplexed
          {
            toValue: 1,
            duration: 500,
            easing: Easing.cubic,
            useNativeDriver: true,
            delay: 200
          }
        )
      ]);

      newAnimations.push({
        addAnimation,
        scaleAnimation,
        opacityAnimation,
        animation
      });
    }
    setAnimations(newAnimations);
  }, [addGoldCoinNum, scale, x, y]);

  useEffect((): (() => void) => {
    if (animations.length === 0) return (): void => {};
    const moveTimer = Animated.stagger(
      200,
      animations.map((item): Animated.CompositeAnimation => item.animation)
    );

    moveTimer.start((): void => {
      setAnimations([]);
      clearGoldCoinNum();
    });

    const hideTimer = setTimeout((): void => {
      if (hideGoldCoinNum) {
        hideGoldCoinNum();
      }
      if (!needBaseGoldCoin) {
        setLocalShowAddNumber(false);
      }
    }, 700);

    const soundTimer = setTimeout((): void => {
      if (needSound) {
        playSoundWithUrl({
          url:
            'https://yte-resource-audio.oss-cn-hangzhou.aliyuncs.com/gold/gold.mp3'
        });
      }
    }, 500);
    return (): void => {
      if (hideTimer) {
        clearTimeout(hideTimer);
      }
      if (soundTimer) {
        clearTimeout(soundTimer);
      }
    };
  }, [animations, needSound]);

  return useMemo((): ReactElement => {
    return (
      <View style={[styles.content, style]}>
        <View style={[styles.coinList, { width, height }, coinStyle]}>
          {needBaseGoldCoin && (
            <Image
              style={[styles.coin, { width, height }, coinStyle]}
              source={classRoomGold}
              resizeMode="contain"
            />
          )}
          {animations.map(
            (item): ReactElement => (
              <Animated.Image
                style={[
                  styles.coin,
                  { width, height },
                  coinStyle,
                  {
                    transform: [
                      { translateX: item.addAnimation.x }, // x轴移动
                      { translateY: item.addAnimation.y }, // y轴移动
                      { scale: item.scaleAnimation }
                    ]
                  },
                  {
                    opacity: item.opacityAnimation
                  }
                ]}
                source={classRoomGold}
              />
            )
          )}
        </View>
        {localShowAddNumber && showAddNumber && !children && (
          <Text
            style={[
              styles.number,
              { left: phonePx(5) * CLASS_ROOM_RIGHT_SCALE + width }
            ]}
          >
            +{addGoldCoinNum}
          </Text>
        )}
        {localShowAddNumber && children}
      </View>
    );
  }, [
    addGoldCoinNum,
    animations,
    children,
    coinStyle,
    height,
    localShowAddNumber,
    needBaseGoldCoin,
    showAddNumber,
    style,
    width
  ]);
};
